package kit.docker.database;

import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.docker.core.constant.ConfigConstant;
import com.jfinal.config.Plugins;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.CaseInsensitiveContainerFactory;
import com.jfinal.plugin.activerecord.dialect.*;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.template.source.ClassPathSourceFactory;

import java.sql.Connection;
import java.util.LinkedHashMap;
import java.util.Map;

public abstract class DataBaseConnectKit {

    private static final Map<String, DataBaseBean> dbMap = new LinkedHashMap<String, DataBaseBean>();

    /**
     * 获取所有数据源配置对象
     *
     * @return 数据源对象Map集合
     */
    public static Map<String, DataBaseBean> getDbMap() {
        if (dbMap.isEmpty()) {
            parseDbInfo();
        }
        return dbMap;
    }

    /**
     * 获取指定数据源对象
     *
     * @param name 数据源名称
     * @return 数据源配置对象
     */
    public static DataBaseBean getDbMap(String name) {
        if (dbMap.isEmpty()) {
            parseDbInfo();
        }
        return dbMap.get(name);
    }

    /**
     * 封装数据源
     */
    private static void parseDbInfo() {

        String prefix = null;
        String db_start = "db[";
        String db_end = "]";

        String name = null;
        String dbType = null;
        String driverClass = null;
        String jdbcUrl = null;
        String userName = null;
        String password = null;
        String host = null;
        String port = null;
        String dbName = null;
        boolean sqlEngine = false;
        String sqlTemplate = null;

        int initialSize = 0;
        int minIdle = 0;
        int maxActive = 8;

        DataBaseBean db = null;

        int dbCount = PropKit.getInt(DataBaseConstant.db_count);
        for (int i = 1; i <= dbCount; i++) {
            // 数据源配置参数前缀
            prefix = db_start + i + db_end + ".";
            // 数据源名称
            name = PropKit.get(prefix + DataBaseConstant.db_name);
            // 数据库类型
            dbType = PropKit.get(prefix + DataBaseConstant.db_type).toLowerCase();
            // 数据库驱动
            driverClass = PropKit.get(prefix + DataBaseConstant.db_driver_class);
            // 数据库连接地址
            jdbcUrl = PropKit.get(prefix + DataBaseConstant.db_jdbc_url);
            // 数据库用户名
            userName = PropKit.get(prefix + DataBaseConstant.db_username);
            // 数据库密码
            password = PropKit.get(prefix + DataBaseConstant.db_password);
            initialSize = PropKit.getInt(prefix + DataBaseConstant.db_initial_size);
            minIdle = PropKit.getInt(prefix + DataBaseConstant.db_min_idle);
            maxActive = PropKit.getInt(prefix + DataBaseConstant.db_max_active);
            sqlEngine = PropKit.getBoolean(prefix + DataBaseConstant.db_sql_engine, false);
            sqlTemplate = PropKit.get(prefix + DataBaseConstant.db_sql_template);

            if (dbType.equalsIgnoreCase(DataBaseConstant.db_type_postgresql)) { // PostgreSQL
                // 解析数据库连接URL，获取数据库名称
                dbName = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                dbName = dbName.substring(dbName.indexOf("/") + 1);

                // 解析数据库连接URL，获取数据库地址IP
                host = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                host = host.substring(0, host.indexOf(":"));

                // 解析数据库连接URL，获取数据库地址端口
                port = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                port = port.substring(port.indexOf(":") + 1, port.indexOf("/"));

            } else if (dbType.equalsIgnoreCase(DataBaseConstant.db_type_mysql)) { // MySQL
                // 解析数据库连接URL，获取数据库名称
                dbName = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                dbName = dbName.substring(dbName.indexOf("/") + 1, dbName.indexOf("?"));

                // 解析数据库连接URL，获取数据库地址IP
                host = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                host = host.substring(0, host.indexOf(":"));

                // 解析数据库连接URL，获取数据库地址端口
                port = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                port = port.substring(port.indexOf(":") + 1, port.indexOf("/"));
            } else if (dbType.equalsIgnoreCase(DataBaseConstant.db_type_oracle)) { // Oracle
                // 解析数据库连接URL，获取数据库名称
                String[] prop = jdbcUrl.substring(jdbcUrl.indexOf("@") + 1).split(":");
                dbName = prop[2];

                // 解析数据库连接URL，获取数据库地址IP
                host = prop[0];

                // 解析数据库连接URL，获取数据库地址端口
                port = prop[1];
            } else if (dbType.equalsIgnoreCase(DataBaseConstant.db_type_sqlserver)) { // SQLServer
                // 解析数据库连接URL，获取数据库名称
                dbName = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                dbName = dbName.substring(dbName.indexOf("/") + 1);

                // 解析数据库连接URL，获取数据库地址IP
                host = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                host = host.substring(0, host.indexOf(":"));

                // 解析数据库连接URL，获取数据库地址端口
                port = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                port = port.substring(port.indexOf(":") + 1, port.indexOf("/"));
            } else if (dbType.equalsIgnoreCase(DataBaseConstant.db_type_db2)) { // DB2
                // 解析数据库连接URL，获取数据库名称
                dbName = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                dbName = dbName.substring(dbName.indexOf("/") + 1);

                // 解析数据库连接URL，获取数据库地址IP
                host = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                host = host.substring(0, host.indexOf(":"));

                // 解析数据库连接URL，获取数据库地址端口
                port = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2);
                port = port.substring(port.indexOf(":") + 1, port.indexOf("/"));
            }

            db = new DataBaseBean();
            db.setName(name);
            db.setType(dbType);
            db.setDriverClass(driverClass);
            db.setJdbcUrl(jdbcUrl);
            db.setUserName(userName);
            db.setPassword(password);
            db.setHost(host);
            db.setPort(port);
            db.setDbName(dbName);
            db.setInitialSize(initialSize);
            db.setMinIdle(minIdle);
            db.setMaxActive(maxActive);
            db.setSqlEngine(sqlEngine);
            db.setSqlTemplate(sqlTemplate);

            dbMap.put(name, db);
        }
    }


    public static void connect(Plugins plugins) {
        Map<String, DataBaseBean> dbMap = getDbMap();
        for (String name : dbMap.keySet()) {
            DataBaseBean db = dbMap.get(name);
            DruidPlugin druidPlugin = new DruidPlugin(db.getJdbcUrl(), db.getUserName(), db.getPassword(), db.getDriverClass());
            druidPlugin.set(db.getInitialSize(), db.getMinIdle(), db.getMaxActive());
            WallFilter wallFilter = new WallFilter(); //数据库安全过滤
            wallFilter.setDbType(db.getType());
            //WallConfig wallConfig = new WallConfig();
            //wallConfig.setStrictSyntaxCheck(false);
            //wallConfig.setFunctionCheck(false);
            druidPlugin.addFilter(wallFilter);
            druidPlugin.addFilter(new StatFilter());   // 统计数据支持
            plugins.add(druidPlugin);

            ActiveRecordPlugin arp = new ActiveRecordPlugin(name, druidPlugin);
            arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
            arp.setDevMode(PropKit.getBoolean(ConfigConstant.SYS_DEV_MODEL, false)); // 设置开发模式
            arp.setShowSql(PropKit.getBoolean(ConfigConstant.SYS_DEV_MODEL, false)); // 是否显示SQL
            arp.setContainerFactory(new CaseInsensitiveContainerFactory(true)); // 大小写不敏感
            if (db.getType().equalsIgnoreCase(DataBaseConstant.db_type_postgresql)) {
                arp.setDialect(new PostgreSqlDialect());
            } else if (db.getType().equalsIgnoreCase(DataBaseConstant.db_type_mysql)) {
                arp.setDialect(new MysqlDialect());
            } else if (db.getType().equalsIgnoreCase(DataBaseConstant.db_type_oracle)) {
                arp.setDialect(new OracleDialect());
            } else if (db.getType().equalsIgnoreCase(DataBaseConstant.db_type_sqlserver)) {
                arp.setDialect(new SqlServerDialect());
            } else if (db.getType().equalsIgnoreCase(DataBaseConstant.db_type_db2)) {
                arp.setDialect(new AnsiSqlDialect());
            }
            if (db.isSqlEngine()) {
                arp.getEngine().setSourceFactory(new ClassPathSourceFactory());
                //arp.setBaseSqlTemplatePath(PathKit.getRootClassPath());
                arp.addSqlTemplate(db.getSqlTemplate());
            }
            plugins.add(arp);
        }
    }
}
